package com.xwj.service.Impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xwj.Enums.StatusInfoEnum;
import com.xwj.dao.RaHourseInfoDao;
import com.xwj.dto.HouseInfoDto;
import com.xwj.entity.HouseInfoDetailEntity;
import com.xwj.entity.RaHourseInfo;
import com.xwj.service.Interface.RaHouseInfoService;
import com.xwj.service.redis.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;

@Slf4j
@Service
@CacheConfig(cacheNames = "RaHouseInfoCache")
public class RaHouseInfoServiceImpl implements RaHouseInfoService {

    @Autowired
    private RaHourseInfoDao raHourseInfoDao;
    @Autowired
    private RaStatusInfoServiceImpl raStatusInfoService;
    @Autowired
    private RedisService redisService;

    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();  //读写锁

    private Lock lock = readWriteLock.readLock();

    @Override
    @Cacheable(key = "#root.methodName", unless = "#result.size() == 0")
    public List<RaHourseInfo> findAllHouseInfo() {
        lock.lock();
        try {
            return raHourseInfoDao.findAllHouseInfo();
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return Collections.emptyList();
        } finally {
            lock.unlock();
        }
    }

    @Override
    @Cacheable(key = "#root.methodName+'_'+ #pageIndex + '_cloudId_'+ #cloudId", unless = "#result.list.size() == 0")
    public PageInfo<RaHourseInfo> findHouseInfoByCloudId(int pageIndex, int pageSize, int cloudId) {
        PageHelper.startPage(pageIndex, pageSize);
        lock.lock();
        try {
            String label = StatusInfoEnum.HouseInfo.getName();
            List<RaHourseInfo> raHourseInfoList = raHourseInfoDao.findHouseInfoByCloudId(cloudId);
            raHourseInfoList.forEach(raHourseInfo -> {
                Map<String, Object> map = new HashMap<>();
                map.put("label", label);
                map.put("type", raHourseInfo.getStatus());
                String status = raStatusInfoService.findOneStatus(map);
                raHourseInfo.setStatusStr(status);
            });
            PageInfo<RaHourseInfo> pageInfo = new PageInfo<>(raHourseInfoList);
            return pageInfo;
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return new PageInfo<>(Collections.emptyList());
        } finally {
            lock.unlock();
        }
    }

    @Override
    @Cacheable(key = "#root.methodName+'_'+ #pageIndex + '_cloudId_'+ #cloudId", unless = "#result.list.size() == 0")
    public PageInfo<RaHourseInfo> frontFindHouseInfoByCloudId(int pageIndex, int pageSize, int cloudId) {
        PageHelper.startPage(pageIndex, pageSize);
        lock.lock();
        try {
            String label = StatusInfoEnum.HouseInfo.getName();
            List<RaHourseInfo> raHourseInfoList = raHourseInfoDao.frontFindHouseInfoByCloudId(cloudId);
            raHourseInfoList.forEach(raHourseInfo -> {
                Map<String, Object> map = new HashMap<>();
                map.put("label", label);
                map.put("type", raHourseInfo.getStatus());
                String status = raStatusInfoService.findOneStatus(map);
                raHourseInfo.setStatusStr(status);
            });
            PageInfo<RaHourseInfo> pageInfo = new PageInfo<>(raHourseInfoList);
            return pageInfo;
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return new PageInfo<>(Collections.emptyList());
        } finally {
            lock.unlock();
        }
    }

    @Override
    @Cacheable(key = "#root.methodName+'_cloudId_'+ #cloudId", unless = "#result.size() == 0")
    public List<RaHourseInfo> frontFindHouseInfoByCloudIdWithNoPage(int cloudId) {
        lock.lock();
        try {
            String label = StatusInfoEnum.HouseInfo.getName();
            List<RaHourseInfo> raHourseInfoList = raHourseInfoDao.frontFindHouseInfoByCloudId(cloudId);
            raHourseInfoList.forEach(raHourseInfo -> {
                Map<String, Object> map = new HashMap<>();
                map.put("label", label);
                map.put("type", raHourseInfo.getStatus());
                String status = raStatusInfoService.findOneStatus(map);
                raHourseInfo.setStatusStr(status);
                raHourseInfo.setHouseInfoDetailEntity(JSON.parseObject(raHourseInfo.getDetailInfo(), new TypeReference<HouseInfoDetailEntity>() {
                }));
            });
            return raHourseInfoList;
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return Collections.emptyList();
        } finally {
            lock.unlock();
        }
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public int deleteByIds(List<String> ids) {
        try {
            return raHourseInfoDao.deleteByIds(ids);
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return 0;
        }
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public int updateProperty(HouseInfoDto houseInfoDto) {
        try {
            return raHourseInfoDao.updateProperty(houseInfoDto);
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return 0;
        }
    }

    @Override
    @Async("houseInfoTaskAsyncPool")
    @CacheEvict(allEntries = true)
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Future<Boolean> updatePropertySync(HouseInfoDto houseInfoDto) {
        Future<Boolean> future;
        try {
            raHourseInfoDao.updateProperty(houseInfoDto);
            future = new AsyncResult<>(true);
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            future = new AsyncResult<>(false);
        }
        return future;
    }

    /**
     * 查询
     *
     * @param pageIndex
     * @param pageSize
     * @param houseInfoDto
     * @return
     */
    @Override
    @Cacheable(key = "#root.methodName+'_'+ #pageIndex + '_attr_'+ #houseInfoDto.toString()", unless = "#result.list.size() == 0")
    public PageInfo<RaHourseInfo> findByProperty(int pageIndex, int pageSize, HouseInfoDto houseInfoDto) {
        PageHelper.startPage(pageIndex, pageSize);
        lock.lock();
        try {
            String label = StatusInfoEnum.HouseInfo.getName();
            List<RaHourseInfo> raHourseInfoList = raHourseInfoDao.findByProperty(houseInfoDto);
            raHourseInfoList.forEach(raHourseInfo -> {
                Map<String, Object> map = new HashMap<>();
                map.put("label", label);
                map.put("type", raHourseInfo.getStatus());
                String status = raStatusInfoService.findOneStatus(map);
                raHourseInfo.setStatusStr(status);
            });
            PageInfo<RaHourseInfo> pageInfo = new PageInfo<>(raHourseInfoList);
            return pageInfo;
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return new PageInfo<>(Collections.emptyList());
        } finally {
            lock.unlock();
        }
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public int insertOneHouse(RaHourseInfo raHourseInfo) {
        try {
            return raHourseInfoDao.insertOneHouse(raHourseInfo);
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return 0;
        }
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public int updateDetail(Map<String, Object> map) {
        try {
            return raHourseInfoDao.updateDetail(map);
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return 0;
        }
    }

    @Override
    @Cacheable(key = "#root.methodName + '_'+#id", unless = "#result == null")
    public RaHourseInfo findHouseInfoById(String id) {
        try {
            return raHourseInfoDao.findHouseInfoById(id);
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return null;
        }
    }

    @Override
    @Cacheable(key = "#root.methodName + '_'+#id", unless = "#result == null")
    public RaHourseInfo findHouseInfoByIdSync(String id) {
        lock.lock();
        try {
            RaHourseInfo raHourseInfo = raHourseInfoDao.findHouseInfoById(id);
            String label = StatusInfoEnum.HouseInfo.getName();
            Map<String, Object> map = new HashMap<>();
            map.put("label", label);
            map.put("type", raHourseInfo.getStatus());
            String status = raStatusInfoService.findOneStatus(map);
            raHourseInfo.setStatusStr(status);
            raHourseInfo.setHouseInfoDetailEntity(JSON.parseObject(raHourseInfo.getDetailInfo(), new TypeReference<HouseInfoDetailEntity>() {
            }));
            return raHourseInfo;
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return null;
        } finally {
            lock.unlock();
        }
    }


    @Override
    @Cacheable(key = "#root.methodName+'_'+ #pageIndex + '_userId_'+ #userId", unless = "#result.list.size() == 0")
    public PageInfo<RaHourseInfo> findHouseInfoByUserId(int pageIndex, int pageSize, String userId) {
        PageHelper.startPage(pageIndex, pageSize);
        try {
            String label = StatusInfoEnum.HouseInfo.getName();
            List<RaHourseInfo> raHourseInfoList = raHourseInfoDao.findHouseInfoByUserId(userId);
            raHourseInfoList.forEach(raHourseInfo -> {
                Map<String, Object> map = new HashMap<>();
                map.put("label", label);
                map.put("type", raHourseInfo.getStatus());
                String status = raStatusInfoService.findOneStatus(map);
                raHourseInfo.setStatusStr(status);
            });
            PageInfo<RaHourseInfo> pageInfo = new PageInfo<>(raHourseInfoList);
            return pageInfo;
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return new PageInfo<>(Collections.emptyList());
        }
    }

    @Override
    @Cacheable(key = "#root.methodName+'_'+ #pageIndex + '_attr_'+ #houseInfoDto.toString()", unless = "#result.list.size() == 0")
    public PageInfo<RaHourseInfo> frontFindByProperty(int pageIndex, int pageSize, HouseInfoDto houseInfoDto) {
        PageHelper.startPage(pageIndex, pageSize);
        try {
            String label = StatusInfoEnum.HouseInfo.getName();
            List<RaHourseInfo> raHourseInfoList = raHourseInfoDao.frontFindByProperty(houseInfoDto);
            raHourseInfoList.forEach(raHourseInfo -> {
                Map<String, Object> map = new HashMap<>();
                map.put("label", label);
                map.put("type", raHourseInfo.getStatus());
                String status = raStatusInfoService.findOneStatus(map);
                raHourseInfo.setStatusStr(status);
            });
            PageInfo<RaHourseInfo> pageInfo = new PageInfo<>(raHourseInfoList);
            return pageInfo;
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            return new PageInfo<>(Collections.emptyList());
        }
    }

    @Override
    @Async("houseInfoTaskAsyncPool")
    @CacheEvict(allEntries = true)
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Future<Boolean> updateDelflag(List<String> ids) {
        Future<Boolean> future;
        try {
            raHourseInfoDao.updateDelflag(ids);
            future = new AsyncResult<>(true);
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            future = new AsyncResult<>(false);
        }
        return future;
    }

    @Override
    @Async("houseInfoTaskAsyncPool")
    @CacheEvict(allEntries = true)
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Future<Boolean> updateStatus(Map<String, Object> map) {
        Future<Boolean> future;
        try {
            raHourseInfoDao.updateStatus(map);
            future = new AsyncResult<>(true);
        } catch (Exception e) {
            log.error("RaHouseInfoService异常:", e);
            e.printStackTrace();
            future = new AsyncResult<>(false);
        }
        return future;
    }

    /**
     * 将图片链接缓存起来
     *
     * @param accressUrl
     * @param key
     * @return
     */
    public void accressUrlSet(String accressUrl, String key) {
        redisService.add(key, accressUrl, 3600);
    }

    public Set<Object> getAccressUrlSet(String key) {
        Set<Object> urlStr = new HashSet<>();
        if (redisService.exists(key))
            urlStr = redisService.setMembers(key);
        return urlStr;
    }


    public void deleteSet(String key) {
        redisService.remove(key);
    }


    public List<String> parseListId(List<RaHourseInfo> raHourseInfos) {
        return raHourseInfos.stream().map(RaHourseInfo::getId).collect(Collectors.toList());
    }
}
